// 文件路径: src/main/java/com/cupk/services/DashboardService.java (最终优化版)
// 请用此代码完整替换您现有的文件

package com.cupk.services;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cupk.dtos.DashboardDataDto;
import com.cupk.entities.Project;
import com.cupk.entities.Task;
import com.cupk.entities.User;
import com.cupk.exceptions.ResourceNotFoundException;
import com.cupk.mapper.*;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
@RequiredArgsConstructor
public class DashboardService {

    private final UserMapper userMapper;
    private final ProjectMapper projectMapper;
    private final TaskMapper taskMapper;
    private final PublicationMapper publicationMapper;
    private final FundingMapper fundingMapper;

    @Transactional(readOnly = true)
    public DashboardDataDto getDashboardData(String username) {
        User user = findUserByUsername(username);
        Long userId = user.getId();

        DashboardDataDto data = new DashboardDataDto();

        data.setInProgressProjects(calculateKpi(projectMapper.countInProgressForUser(userId), projectMapper.countInProgressForUserLastMonth(userId)));
        data.setInProgressTasks(calculateKpi(taskMapper.countInProgressForUser(userId), taskMapper.countInProgressForUserLastMonth(userId)));
        data.setPublishedPublications(calculateKpi(publicationMapper.countPublishedForUser(userId), publicationMapper.countPublishedForUserLastMonth(userId)));

        // 调用修复后的预算计算方法
        data.setBudgetUsage(calculateBudgetUsageKpi(userId));

        data.setProjectProgress(getProjectProgress(userId));
        data.setTaskDistribution(taskMapper.getTaskDistributionForUser(userId));

        // 【已优化】调用优化后的最近活动方法
        data.setRecentActivities(getRecentActivities(userId));

        return data;
    }

    @Transactional(readOnly = true)
    public List<DashboardDataDto.MonthlyChartPoint> getMonthlyTrendData(String username, String type) {
        User user = findUserByUsername(username);
        Long userId = user.getId();

        List<DashboardDataDto.MonthlyChartPoint> dbResults;

        switch (type.toUpperCase()) {
            case "PROJECTS":
                dbResults = projectMapper.getMonthlyTrendForUser(userId, LocalDate.now().getYear());
                break;
            case "TASKS":
                dbResults = taskMapper.getMonthlyTrendForUser(userId, LocalDate.now().getYear());
                break;
            case "PUBLICATIONS":
                dbResults = publicationMapper.getMonthlyTrendForUser(userId, LocalDate.now().getYear());
                break;
            case "BUDGET":
                dbResults = fundingMapper.getMonthlyExpenseTrendForUser(userId, LocalDate.now().getYear());
                break;
            default:
                dbResults = projectMapper.getMonthlyTrendForUser(userId, LocalDate.now().getYear());
        }

        // 【已优化】调用新的方法，确保返回连续的月份
        return generateContinuousMonthlyData(dbResults);
    }

    // --- 私有辅助方法 ---

    private User findUserByUsername(String username) {
        User user = userMapper.selectOne(new QueryWrapper<User>().eq("username", username));
        if (user == null) throw new ResourceNotFoundException("用户未找到: " + username);
        return user;
    }

    private DashboardDataDto.KpiCard calculateKpi(long currentValue, long previousValue) {
        DashboardDataDto.KpiCard card = new DashboardDataDto.KpiCard();
        card.setValue(currentValue);
        if (previousValue == 0) {
            card.setTrend(currentValue > 0 ? 1.0 : 0.0);
        } else {
            double trend = ((double) (currentValue - previousValue) / previousValue);
            card.setTrend(trend);
        }
        return card;
    }

    private DashboardDataDto.KpiCard calculateBudgetUsageKpi(Long userId) {
        DashboardDataDto.KpiCard card = new DashboardDataDto.KpiCard();
        BigDecimal totalBudget = projectMapper.sumBudgetForUserProjects(userId);
        BigDecimal totalExpense = fundingMapper.sumApprovedExpenseForUserProjects(userId);

        totalBudget = (totalBudget == null) ? BigDecimal.ZERO : totalBudget;
        totalExpense = (totalExpense == null) ? BigDecimal.ZERO : totalExpense;

        if (totalBudget.compareTo(BigDecimal.ZERO) == 0) {
            card.setValue(0);
            card.setTrend(0.0);
            return card;
        }

        BigDecimal usageRate = totalExpense.divide(totalBudget, 4, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
        card.setValue(usageRate.longValue());

        card.setTrend(0.0);
        return card;
    }

    private List<DashboardDataDto.ProjectProgressItem> getProjectProgress(Long userId) {
        List<Project> projects = projectMapper.findInProgressWithTaskCountsForUser(userId);
        return projects.stream().map(p -> {
            DashboardDataDto.ProjectProgressItem item = new DashboardDataDto.ProjectProgressItem();
            item.setProjectId(p.getId());
            item.setProjectName(p.getProjectName());
            item.setStatus(p.getStatus());

            long totalTasks = p.getMeta().getOrDefault("total_tasks", 0L);
            long completedTasks = p.getMeta().getOrDefault("completed_tasks", 0L);

            if (totalTasks == 0) {
                item.setProgress(0);
            } else {
                item.setProgress((int) Math.round(((double) completedTasks / totalTasks) * 100));
            }
            return item;
        }).collect(Collectors.toList());
    }

    /**
     * 【已优化】最近活动获取方法
     * 现在会合并来自任务、项目和成果的最近更新，内容更丰富。
     */
    private List<DashboardDataDto.ActivityItem> getRecentActivities(Long userId) {
        // 获取最近更新的任务
        List<Task> recentTasks = taskMapper.findRecentActivitiesForUser(userId, 5);
        Stream<DashboardDataDto.ActivityItem> taskActivities = recentTasks.stream().map(t -> {
            DashboardDataDto.ActivityItem item = new DashboardDataDto.ActivityItem();
            item.setEntityId(t.getId());
            item.setDescription("任务 “" + t.getTitle() + "” 状态更新为 " + t.getStatus());
            item.setTimestamp(formatRelativeTime(t.getUpdatedAt()));
            item.setType("TASK");
            return item;
        });

        // 【新增】获取最近创建的项目
        List<Project> recentProjects = projectMapper.findRecentCreatedForUser(userId, 5); // 【需要新Mapper方法】
        Stream<DashboardDataDto.ActivityItem> projectActivities = recentProjects.stream().map(p -> {
            DashboardDataDto.ActivityItem item = new DashboardDataDto.ActivityItem();
            item.setEntityId(p.getId());
            item.setDescription("您参与的新项目 “" + p.getProjectName() + "” 已创建");
            item.setTimestamp(formatRelativeTime(p.getCreatedAt()));
            item.setType("PROJECT");
            return item;
        });

        // 将所有活动流合并，按时间排序，并取最新的5条
        return Stream.concat(taskActivities, projectActivities)
                .sorted(Comparator.comparing(DashboardDataDto.ActivityItem::getTimestamp).reversed())
                .limit(5)
                .collect(Collectors.toList());
    }

    /**
     * 【已优化】生成连续的月度数据
     * 这个方法确保图表X轴是连续的，即使某个月份没有数据。
     */
    private List<DashboardDataDto.MonthlyChartPoint> generateContinuousMonthlyData(List<DashboardDataDto.MonthlyChartPoint> dbResults) {
        // 创建一个从1月到当前月份的月份列表
        int currentMonth = LocalDate.now().getMonthValue();
        Map<String, DashboardDataDto.MonthlyChartPoint> resultMap = new LinkedHashMap<>();
        for (int i = 1; i <= currentMonth; i++) {
            String monthKey = i + "月";
            DashboardDataDto.MonthlyChartPoint point = new DashboardDataDto.MonthlyChartPoint();
            point.setMonth(monthKey);
            // 【重要修改】确保 value 被初始化为正确的类型
            point.setValue(BigDecimal.ZERO);
            resultMap.put(monthKey, point);
        }

        // 将数据库查询到的结果填入Map中
        if (dbResults != null) {
            for (DashboardDataDto.MonthlyChartPoint dbPoint : dbResults) {
                if (resultMap.containsKey(dbPoint.getMonth())) {
                    resultMap.get(dbPoint.getMonth()).setValue(dbPoint.getValue());
                }
            }
        }

        return new ArrayList<>(resultMap.values());
    }

    private String formatRelativeTime(LocalDateTime time) {
        if (time == null) return "";
        Duration duration = Duration.between(time, LocalDateTime.now());
        long hours = duration.toHours();
        if (hours < 1) return duration.toMinutes() + "分钟前";
        if (hours < 24) return hours + "小时前";
        return duration.toDays() + "天前";
    }
}